/*
 * Copyright (c) 2024 OpenHiTLS. All rights reserved.
 * Licensed under the OpenHiTLS license.
 */
package org.openhitls.core;

/**
 * Central entry point for all native cryptographic and TLS operations.
 * This class contains JNI method declarations for the native openHiTLS library.
 *
 * <p>Note: Package change from org.openhitls.crypto.core to org.openhitls.core
 * requires corresponding updates to JNI function names in the native C code.</p>
 */
public class CryptoNative {

    // ==================== Hash/MessageDigest Native Methods ====================

    /**
     * Initialize a message digest context for the specified algorithm.
     * @param algorithm Hash algorithm name (e.g., "SHA-256", "SM3")
     * @return Native context pointer
     */
    public static native long messageDigestInit(String algorithm);

    /**
     * Update the message digest with data.
     * @param contextPtr Native context pointer
     * @param data Data to hash
     * @param offset Start offset in data array
     * @param length Number of bytes to process
     */
    public static native void messageDigestUpdate(long contextPtr, byte[] data, int offset, int length);

    /**
     * Finalize the message digest and return the hash value.
     * @param contextPtr Native context pointer
     * @return Hash value
     */
    public static native byte[] messageDigestFinal(long contextPtr);

    /**
     * Free the message digest context.
     * @param contextPtr Native context pointer
     */
    public static native void messageDigestFree(long contextPtr);

    // ==================== HMAC Native Methods ====================

    public static native long hmacInit(String algorithm, byte[] key);
    public static native void hmacUpdate(long contextPtr, byte[] data, int offset, int length);
    public static native byte[] hmacFinal(long contextPtr);
    public static native void hmacReinit(long contextPtr);
    public static native int hmacGetMacLength(long contextPtr);
    public static native void hmacFree(long contextPtr);

    // ==================== ECDSA/SM2 Native Methods ====================

    public static native long ecdsaCreateContext(String curveName);
    public static native void ecdsaFreeContext(long nativeRef);
    public static native void ecdsaSetKeys(long nativeRef, String curveName, byte[] publicKey, byte[] privateKey);
    public static native void ecdsaSetUserId(long nativeRef, byte[] userId);
    public static native byte[][] ecdsaGenerateKeyPair(long nativeRef, String curveName);
    public static native byte[] ecdsaEncrypt(long nativeRef, byte[] data);
    public static native byte[] ecdsaDecrypt(long nativeRef, byte[] encryptedData);
    public static native byte[] ecdsaSign(long nativeRef, byte[] data, int hashAlg);
    public static native boolean ecdsaVerify(long nativeRef, byte[] data, byte[] signature, int hashAlg);

    // ==================== Symmetric Cipher Native Methods ====================

    public static native long symmetricCipherInit(String algorithm, String cipherMode, byte[] key, byte[] iv, int mode);
    public static native void symmetricCipherSetPadding(long contextPtr, int paddingType);
    public static native void symmetricCipherUpdate(long contextPtr, byte[] input, int inputOffset, int inputLen,
                                             byte[] output, int outputOffset, int[] outLen);
    public static native byte[] symmetricCipherFinal(long contextPtr);
    public static native void symmetricCipherFree(long contextPtr);

    // GCM specific methods
    public static native void symmetricCipherSetAAD(long contextPtr, byte[] aad, int offset, int len);
    public static native void symmetricCipherSetTagLen(long contextPtr, int tagLen);
    public static native void symmetricCipherGetTag(long contextPtr, byte[] tag, int tagLen);

    // ==================== DSA Native Methods ====================

    public static native long dsaCreateContext();
    public static native void dsaFreeContext(long nativeRef);
    public static native void dsaSetParameters(long nativeRef, byte[] p, byte[] q, byte[] g);
    public static native void dsaSetKeys(long nativeRef, byte[] publicKey, byte[] privateKey);
    public static native byte[][] dsaGenerateKeyPair(long nativeRef);
    public static native byte[] dsaSign(long nativeRef, byte[] data, int hashAlg);
    public static native boolean dsaVerify(long nativeRef, byte[] data, byte[] signature, int hashAlg);

    // ==================== RSA Native Methods ====================

    public static native long rsaCreateContext();
    public static native void rsaFreeContext(long nativeRef);
    public static native void rsaSetParameters(long nativeRef, byte[] e, int keyBits);
    public static native void rsaSetKeys(long nativeRef, byte[] publicKey, byte[] privateKey);
    public static native void rsaSetPadding(long nativeRef, int paddingMode);
    public static native byte[][] rsaGenerateKeyPair(long nativeRef);
    public static native byte[] rsaSign(long nativeRef, byte[] data, String digestAlgorithm);
    public static native boolean rsaVerify(long nativeRef, byte[] data, byte[] signature, String digestAlgorithm);
    public static native byte[] rsaEncrypt(long nativeRef, byte[] data);
    public static native byte[] rsaDecrypt(long nativeRef, byte[] encryptedData);

    // RSA-PSS support
    public static native byte[] rsaSignPSS(long nativeRef, byte[] data, String digestAlgorithm,
                                         String mgf1Algorithm, int saltLength, int trailerField);
    public static native boolean rsaVerifyPSS(long nativeRef, byte[] data, byte[] signature,
                                            String digestAlgorithm, String mgf1Algorithm,
                                            int saltLength, int trailerField);

    // ==================== TLS/SSL Native Methods ====================
    // These methods support SSLEngine (non-blocking/memory BIO) mode

    /**
     * TLS protocol version constants.
     */
    public static final int TLS_VERSION_1_2 = 0x0303;
    public static final int TLS_VERSION_1_3 = 0x0304;

    /**
     * TLS connection mode constants.
     * Note: 1 = client mode, 0 = server mode (matches native HITLS expectations)
     */
    public static final int TLS_MODE_CLIENT = 1;
    public static final int TLS_MODE_SERVER = 0;

    /**
     * TLS operation result constants.
     */
    public static final int TLS_SUCCESS = 0;
    public static final int TLS_WANT_READ = 1;
    public static final int TLS_WANT_WRITE = 2;
    public static final int TLS_ERROR = -1;
    public static final int TLS_CLOSED = -2;

    // ----- SSL Context Management -----

    /**
     * Create a new SSL context for the specified TLS version.
     * @param minVersion Minimum TLS version (e.g., TLS_VERSION_1_2)
     * @param maxVersion Maximum TLS version (e.g., TLS_VERSION_1_3)
     * @return Native SSL_CTX pointer
     */
    public static native long sslCtxNew(int minVersion, int maxVersion);

    /**
     * Free an SSL context.
     * @param ctxPtr Native SSL_CTX pointer
     */
    public static native void sslCtxFree(long ctxPtr);

    /**
     * Set SSL context options.
     * @param ctxPtr Native SSL_CTX pointer
     * @param options Option flags
     * @return Updated options
     */
    public static native long sslCtxSetOptions(long ctxPtr, long options);

    /**
     * Load certificate chain into the SSL context.
     * @param ctxPtr Native SSL_CTX pointer
     * @param certData Certificate data in DER or PEM format
     * @param format Certificate format (0=DER, 1=PEM)
     */
    public static native void sslCtxSetCertificate(long ctxPtr, byte[] certData, int format);

    /**
     * Load private key into the SSL context.
     * @param ctxPtr Native SSL_CTX pointer
     * @param keyData Private key data in DER or PEM format
     * @param format Key format (0=DER, 1=PEM)
     */
    public static native void sslCtxSetPrivateKey(long ctxPtr, byte[] keyData, int format);

    /**
     * Set the cipher suites for TLS 1.2 and below.
     * @param ctxPtr Native SSL_CTX pointer
     * @param cipherSuites Colon-separated cipher suite string
     */
    public static native void sslCtxSetCipherSuites(long ctxPtr, String cipherSuites);

    /**
     * Set the cipher suites for TLS 1.3.
     * @param ctxPtr Native SSL_CTX pointer
     * @param cipherSuites Colon-separated cipher suite string
     */
    public static native void sslCtxSetCipherSuitesTls13(long ctxPtr, String cipherSuites);

    /**
     * Set trusted CA certificates for peer verification.
     * @param ctxPtr Native SSL_CTX pointer
     * @param caCertData CA certificate data
     * @param format Certificate format (0=DER, 1=PEM)
     */
    public static native void sslCtxSetTrustCertificate(long ctxPtr, byte[] caCertData, int format);

    /**
     * Set peer verification mode.
     * @param ctxPtr Native SSL_CTX pointer
     * @param mode Verification mode (0=none, 1=peer, 2=fail_if_no_peer_cert)
     */
    public static native void sslCtxSetVerifyMode(long ctxPtr, int mode);

    /**
     * Enable or disable trust-all mode (accept any certificate without verification).
     * This is for testing purposes only - do not use in production.
     * @param ctxPtr Native SSL_CTX pointer
     * @param trustAll true to trust all certificates, false to use normal verification
     */
    public static native void sslCtxSetTrustAll(long ctxPtr, boolean trustAll);

    /**
     * Enable certificate chain verification using system CA certificates.
     * This loads CA certificates from standard system locations and enables
     * full certificate chain validation.
     * @param ctxPtr Native SSL_CTX pointer
     */
    public static native void sslCtxEnableVerification(long ctxPtr);

    /**
     * Load CA certificates from a file for peer certificate verification.
     * @param ctxPtr Native SSL_CTX pointer
     * @param filePath Path to CA certificate file (PEM format)
     * @return 0 on success, error code on failure
     */
    public static native int sslCtxLoadVerifyFile(long ctxPtr, String filePath);

    // ----- SSL Session Management -----

    /**
     * Create a new SSL session from a context.
     * @param ctxPtr Native SSL_CTX pointer
     * @return Native SSL pointer
     */
    public static native long sslNew(long ctxPtr);

    /**
     * Free an SSL session.
     * @param sslPtr Native SSL pointer
     */
    public static native void sslFree(long sslPtr);

    /**
     * Set the SSL session to client or server mode.
     * @param sslPtr Native SSL pointer
     * @param mode TLS_MODE_CLIENT or TLS_MODE_SERVER
     */
    public static native void sslSetConnectState(long sslPtr, int mode);

    /**
     * Set the hostname for SNI (Server Name Indication).
     * @param sslPtr Native SSL pointer
     * @param hostname Server hostname
     */
    public static native void sslSetHostname(long sslPtr, String hostname);

    /**
     * Perform the TLS handshake.
     * @param sslPtr Native SSL pointer
     * @return TLS_SUCCESS, TLS_WANT_READ, TLS_WANT_WRITE, or TLS_ERROR
     */
    public static native int sslDoHandshake(long sslPtr);

    /**
     * Check if the handshake is complete.
     * @param sslPtr Native SSL pointer
     * @return true if handshake is complete
     */
    public static native boolean sslIsHandshakeComplete(long sslPtr);

    /**
     * Initiate a graceful TLS shutdown.
     * @param sslPtr Native SSL pointer
     * @return TLS_SUCCESS, TLS_WANT_READ, TLS_WANT_WRITE, or TLS_ERROR
     */
    public static native int sslShutdown(long sslPtr);

    // ----- Application Data Read/Write (plaintext) -----

    /**
     * Write application data (plaintext) to the SSL session.
     * Data will be encrypted and placed in the outbound network buffer.
     * @param sslPtr Native SSL pointer
     * @param data Application data to encrypt and send
     * @param offset Offset in data array
     * @param length Number of bytes to write
     * @return Number of bytes written, or negative on error
     */
    public static native int sslWrite(long sslPtr, byte[] data, int offset, int length);

    /**
     * Read application data (plaintext) from the SSL session.
     * Decrypts data from the inbound network buffer.
     * @param sslPtr Native SSL pointer
     * @param buffer Buffer to receive decrypted data
     * @param offset Offset in buffer
     * @param length Maximum bytes to read
     * @return Number of bytes read, 0 if no data available, or negative on error
     */
    public static native int sslRead(long sslPtr, byte[] buffer, int offset, int length);

    // ----- BIO Network Data Operations (ciphertext) -----
    // These methods handle encrypted network data for SSLEngine-style operation

    /**
     * Write encrypted network data into the SSL engine (received from network).
     * This feeds ciphertext into SSL for decryption.
     * @param sslPtr Native SSL pointer
     * @param data Encrypted data received from network
     * @param offset Offset in data array
     * @param length Number of bytes to write
     * @return Number of bytes consumed, or negative on error
     */
    public static native int sslBioWriteNetData(long sslPtr, byte[] data, int offset, int length);

    /**
     * Read encrypted network data from the SSL engine (to send to network).
     * This retrieves ciphertext produced by SSL after encryption.
     * @param sslPtr Native SSL pointer
     * @param buffer Buffer to receive encrypted data
     * @param offset Offset in buffer
     * @param length Maximum bytes to read
     * @return Number of bytes read, 0 if no data pending, or negative on error
     */
    public static native int sslBioReadNetData(long sslPtr, byte[] buffer, int offset, int length);

    /**
     * Check how many bytes are pending in the read BIO (network data available).
     * @param sslPtr Native SSL pointer
     * @return Number of bytes pending
     */
    public static native int sslBioPendingRead(long sslPtr);

    /**
     * Check how many bytes are pending in the write BIO (encrypted data to send).
     * @param sslPtr Native SSL pointer
     * @return Number of bytes pending
     */
    public static native int sslBioPendingWrite(long sslPtr);

    // ----- Session Information -----

    /**
     * Get the negotiated TLS protocol version.
     * @param sslPtr Native SSL pointer
     * @return Protocol version (e.g., TLS_VERSION_1_3)
     */
    public static native int sslGetVersion(long sslPtr);

    /**
     * Get the negotiated cipher suite name.
     * @param sslPtr Native SSL pointer
     * @return Cipher suite name string
     */
    public static native String sslGetCipherSuite(long sslPtr);

    /**
     * Get the peer's certificate in DER format.
     * @param sslPtr Native SSL pointer
     * @return Peer certificate data, or null if not available
     */
    public static native byte[] sslGetPeerCertificate(long sslPtr);

    /**
     * Get the peer's certificate chain in DER format.
     * @param sslPtr Native SSL pointer
     * @return Array of certificate data, or null if not available
     */
    public static native byte[][] sslGetPeerCertificateChain(long sslPtr);

    /**
     * Get the last SSL error code.
     * @param sslPtr Native SSL pointer
     * @return Error code
     */
    public static native int sslGetError(long sslPtr);

    /**
     * Get the error message for the last SSL error.
     * @param sslPtr Native SSL pointer
     * @return Error message string
     */
    public static native String sslGetErrorString(long sslPtr);

    /**
     * Get the ALPN negotiated protocol.
     * @param sslPtr Native SSL pointer
     * @return Negotiated protocol name, or null if ALPN not used
     */
    public static native String sslGetAlpnSelected(long sslPtr);

    /**
     * Set ALPN protocols for negotiation.
     * @param ctxPtr Native SSL_CTX pointer
     * @param protocols Array of protocol names (e.g., ["h2", "http/1.1"])
     */
    public static native void sslCtxSetAlpnProtocols(long ctxPtr, String[] protocols);

    /**
     * Get the negotiated key exchange group.
     * @param sslPtr Native SSL pointer
     * @return Group ID (e.g., 23 for secp256r1, 29 for x25519, 4588 for X25519_MLKEM768)
     */
    public static native int sslGetNegotiatedGroup(long sslPtr);

    /**
     * Set the supported key exchange groups for TLS 1.3.
     * @param ctxPtr Native SSL_CTX pointer
     * @param groups Array of group IDs
     */
    public static native void sslCtxSetGroups(long ctxPtr, int[] groups);

    // Key exchange group constants
    public static final int GROUP_SECP256R1 = 23;
    public static final int GROUP_SECP384R1 = 24;
    public static final int GROUP_SECP521R1 = 25;
    public static final int GROUP_X25519 = 29;
    public static final int GROUP_X448 = 30;
    public static final int GROUP_SM2 = 41;
    // Post-quantum hybrid groups (ML-KEM based)
    public static final int GROUP_X25519_MLKEM768 = 4588;
    public static final int GROUP_ECDH_NISTP256_MLKEM768 = 4587;
    public static final int GROUP_ECDH_NISTP384_MLKEM1024 = 4589;
}
